#include <Main/error_signals.h>
#include <base/scope_exit.hpp>
#include <base/backtrace.h>
#include <base/log.h>
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
#include <functional>
#include <map>


namespace Main {

using SignalHandler = void (*) (int);
std::map<int, SignalHandler> _old_handler_map;
extern std::function<void()> error_exit_func;
 
bool _is_recursion_call = false;   

void InstallErrorSignals() 
{
    LogInfo("Installing error signals...");
    // 禁止信号触发
    sigset_t new_sigmask, old_sigmask;
    sigfillset(&new_sigmask);
    sigprocmask(SIG_BLOCK, &new_sigmask, &old_sigmask);

    SetScopeExitAction([&]() { sigprocmask(SIG_SETMASK, &old_sigmask, nullptr); });    

    // 注册信号处理函数
    InstallSignal(SIGSEGV);
    InstallSignal(SIGILL);
    InstallSignal(SIGABRT);
    InstallSignal(SIGBUS);
    InstallSignal(SIGFPE);
    InstallSignal(SIGSYS);
    // 考虑SIGPIPE
}

bool InstallSignal(int signo)
{
    SignalHandler old_handler;
    bool is_succ =false;
    
    old_handler = ::signal(signo, OnErrorSignal);
    is_succ = (SIG_ERR != old_handler);

    _old_handler_map[signo] = old_handler;

    return is_succ;
}

void OnErrorSignal(int signo)
{
    InvokeOldHandler(signo);

    // dump 是否可以扩展成多线程的堆栈
    if (!_is_recursion_call)
    {
        _is_recursion_call = true;
        LogFatal("Receive signal %d", signo);

        const std::string &stack_str = base::DumpBacktrace();
        // LogFatal("main: <%p>\n--------call stack-------\n%s", ::main, stack_str.c_str());
        LogFatal("main: \n--------call stack-------\n%s", stack_str.c_str());
        LogFatal("Process abort!");
        _is_recursion_call = false;
    }
    else 
    {
        LogFatal("Recursion signal %d", signo);
    }

    if (error_exit_func) // 善后处理
    {
        LogInfo(" Call error_exit_func");
        error_exit_func();
    }
        
    
    signal(SIGABRT, SIG_DFL);
    std::abort();
}

void InvokeOldHandler(int signo)
{
    auto iter = _old_handler_map.find(signo);
    if (iter == _old_handler_map.end())
    {
        return;
    }

    const auto &old_handler = iter->second;
    if (SIG_ERR != old_handler &&
        SIG_IGN != old_handler &&
        SIG_DFL != old_handler)    
        old_handler(signo);

}

void UninstallErrorSignals()
{
    // 禁止信号触发
    sigset_t new_sigmask, old_sigmask;
    sigfillset(&new_sigmask);
    sigprocmask(SIG_BLOCK, &new_sigmask, &old_sigmask);
    SetScopeExitAction([&]() {sigprocmask(SIG_SETMASK, &old_sigmask, nullptr);} );    

    for (auto &item: _old_handler_map)
    {
        int signo = item.first;
        auto &old_handler = item.second;

        if (old_handler != SIG_ERR) {
            ::signal(signo, old_handler);
        }
    }

    _old_handler_map.clear();
}

}